package com.manzuo.framework.ibatis;

import java.lang.reflect.Method;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;

import com.google.common.collect.Maps;
import com.manzuo.framework.reflection.ReflectionUtils;
import com.manzuo.framework.utils.SpringContextHolder;

@Aspect
public class DaoMethodAspect {
	
	private DaoImpl dao;
	
	@SuppressWarnings("unused")
	@Pointcut("@annotation(com.manzuo.framework.ibatis.DaoMethod)")
	private void daoMethod() {};
	
	@Around("daoMethod()")
	public Object invoke(ProceedingJoinPoint pjp) throws Throwable {
		Object target = pjp.getTarget();
		Object value = null;
		Signature sign = pjp.getSignature();
		
		Method method = ReflectionUtils.getMethod(target, sign.getName(), pjp.getArgs());
		Class<?> clazz = method.getDeclaringClass();
		
		DaoMethod dm = method.getAnnotation(DaoMethod.class);
		String namespace = dm.namespace();
		if(StringUtils.isBlank(namespace)) {
			namespace = clazz.getName();
		}
		String name = dm.name();
		if(StringUtils.isBlank(namespace)) {
			name = method.getName();
		}
		OperationType type = dm.type();
		
		String statement = namespace + "." + name;
		Map<String, Object> params = Maps.newHashMap();
		
		CodeSignature cs = (CodeSignature)sign;
		String[] parameterNames = cs.getParameterNames();
		Object[] parameters = pjp.getArgs();
		if(parameterNames != null && parameters != null) {			
			for(int i = 0; i < parameterNames.length; i++) {
				String key = parameterNames[i];
				Object val = null;
				if(i < parameters.length) {
					val = parameters[i];
				}
				if(StringUtils.isNotBlank(key)) {
					params.put(key, val);
				}
			}
		}
		if(dao == null) {
			dao = SpringContextHolder.getBean(DaoImpl.class);
		}
		switch(type) {
			case insert : value = dao.insert(statement, params); break;
			case delete : value = dao.delete(statement, params); break;
			case update : value = dao.update(statement, params); break;
			case unique : value = dao.unique(statement, params); break;
			case uniqueLoose : value = dao.uniqueLoose(statement, params); break;
			case list : value = dao.list(statement, params); break;
		}
		
		return value;
	}
	
}
